#pragma once

#define MAX_SENT_LENGTH			4096
#define MAX_WORD_LENGTH			32

#define MAX_WORD_NUM			256
#define MAX_INTERP_NUM			16
#define MAX_SLOT_NUM			16

#define MAX_TOPIC_NUM_NLUHYPO	5
#define MAX_TOPICNAME_LENGTH	32
#define MAX_SLOTNAME_LENGTH		64
#define MAX_SLOTVALUE_LENGTH	256

#include "SRNLUTypeDef.h"
#include "UIOSAL.h"
#include <string>
#include <map>
#include <vector>
#include <string.h>

struct SRHypWord_S
{
	long			wordUserID;
	char			word[MAX_WORD_LENGTH];
	float			wordConf;
	float			wordProb;
	float			wordLMScore;
	int				wordStartTime;
	int				wordEndTime;
	bool			isSRSlot;
	char			srSlotName[MAX_SLOTNAME_LENGTH];

	SRHypWord_S()
	{
		wordUserID		= -1;
		strcpy(word, "");
		wordConf		= -1;
		wordProb		= -1;
		wordLMScore		= -1;
		wordStartTime	= -1;
		wordEndTime		= -1;
		isSRSlot		= false;
		strcpy(srSlotName, "");
	}
};
typedef struct SRHypWord_S SRHypWord;

struct SRHypothesis_S
{
	SREngineType	srSource;
	int				srHypID;
	char			sentence[MAX_SENT_LENGTH];
	float			sentConf;
	float			sentProb;
	float			sentLMScore;
	int				numOfWords;
	int				sentStartTime;
	int				sentEndTime;
	SRHypWord		sentWords[MAX_WORD_NUM];
	
	SRHypothesis_S()
	{
		srSource	= SR_ENGINE_UNKNOWN;
		srHypID		= -1;
		strcpy(sentence, "");
		sentConf	= -1;
		sentProb	= -1;
		sentLMScore = -1;
		numOfWords	= 0;
		sentStartTime = -1;
		sentEndTime	= -1;
	}
};
typedef struct SRHypothesis_S SRHypothesis;

struct NLUSlot_S
{
	char			slotName[MAX_SLOTNAME_LENGTH];
	char			slotValue[MAX_SLOTVALUE_LENGTH];
	float			slotConf;
	int				slotStartPosition;
	int				slotEndPosition;

	NLUSlot_S() {
		strcpy(slotName, "");
		strcpy(slotValue, "");
		slotConf			= -1;
		slotStartPosition	= -1;
		slotEndPosition		= -1;
	}

	NLUSlot_S& operator=(const NLUSlot_S& slot)
	{
		strcpy(slotName, slot.slotName);
		strcpy(slotValue, slot.slotValue);
		slotConf = slot.slotConf;
		slotStartPosition = slot.slotStartPosition;
		slotEndPosition = slot.slotEndPosition;
		return *this;
	}
};
typedef struct NLUSlot_S NLUSlot;

struct NLUInterp_S
{
	float			interpConf;
	int				numOfSlots;
	NLUSlot			slots[MAX_SLOT_NUM];
	
	NLUInterp_S() {
		interpConf	= -1;
		numOfSlots	= 0;
	}

	NLUInterp_S& operator=(const NLUInterp_S& interp)
	{
		interpConf = interp.interpConf;
		numOfSlots = interp.numOfSlots;
		for(int i=0; i<interp.numOfSlots; i++) {
			slots[i] = interp.slots[i];
		}
		return *this;
	}

};
typedef struct NLUInterp_S NLUInterp;

struct NLUHypothesis_S
{
	NLUEngineType	nluSource;
	int				srHypID;
	char			topic[MAX_TOPICNAME_LENGTH];
	float			topicConf;
	int				groupID;
	int				numOfInterps;
	NLUInterp		interpretations[MAX_INTERP_NUM];

	NLUHypothesis_S() {
		nluSource		= NLU_ENGINE_UNKNOWN;
		srHypID			= -1;
		strcpy(topic, "");
		topicConf		= -1;
		groupID			= -1;
		numOfInterps	= 0;
	}

	NLUHypothesis_S& operator=(const NLUHypothesis_S& hyp)
	{
		nluSource = hyp.nluSource;
		srHypID = hyp.srHypID;
		strcpy(topic, hyp.topic);
		topicConf = hyp.topicConf;
		groupID = hyp.groupID;
		numOfInterps = hyp.numOfInterps;
	
		for(int i=0; i<hyp.numOfInterps; i++) {
			interpretations[i] = hyp.interpretations[i];
		}
		return *this;
	}

};
typedef struct NLUHypothesis_S NLUHypothesis;

class SRNLUReference
{
public:
	SRNLUReference(void);
	~SRNLUReference(void);
	
	std::string							audioSource;
	std::string							refSent;
	std::string							refTopic;
	std::map<std::string, std::string>	refSlots;
	std::map<std::string, std::string>	refOtherFields;

	std::string serializeVoConHRL(std::vector<std::string> refFields);
	std::string serializeJSON(void);
	void clear();
};

class SRNLUResult
{
public:
	SRNLUResult(void);
	~SRNLUResult(void);
	
	std::string serializeJSON(void);
	std::string serializeVoConHRL(std::vector<std::string> refFields);
	void deserializeJSON(std::string jsonString);

	void addSRHyp(SRHypothesis hyp);
	void addNLUHyp(NLUHypothesis hyp);

	void addAllSRHyp(SRNLUResult* result);
	void addAllNLUHyp(SRNLUResult* result);
	void addAllHyp(SRNLUResult* result);

	std::vector<SREngineType>  getSREngines(void);
	std::vector<NLUEngineType> getNLUEngines(void);
	
	int getSRHypSize(void);
	int getSRHypSize(SREngineType type);
	SRHypothesis* getSRHyp(int index);
	SRHypothesis* getSRHyp(SREngineType type, int index);
	SRHypothesis* getSRHypByID(int hypoId);

	int getNLUHypSize(void);
	int getNLUHypSize(NLUEngineType type);
	NLUHypothesis* getNLUHyp(int index);
	NLUHypothesis* getNLUHyp(NLUEngineType type, int index);

	SRNLUReference* getReference(void)		{	return &m_reference;	}
	void setReference(SRNLUReference ref)	{	m_reference = ref;		}

	void clearSRHyp();
	void clearNLUHyp();
	void clearAll();

	void printOut();

private:
	std::vector<SRHypothesis>	m_SRHyps;
	std::vector<NLUHypothesis>	m_NLUHyps;
	std::map<SREngineType, std::vector<int> > m_SRHypsLinks;
	std::map<NLUEngineType, std::vector<int> > m_NLUHypsLinks;
	SRNLUReference				m_reference;
};

typedef enum {
	SR_NLU_BATCH_DISABLE,
	SR_NLU_BATCH_SR,
	SR_NLU_BATCH_SR_NLU
} SRNLUBatchTestMode;

class SRNLUBatchTester
{
public:
	static SRNLUBatchTester* getInstance();
	static void create();
	static void release();

	void init(std::string hrlName);
	bool getNextTestCase(SRNLUReference &ref);
	
	bool isTestNLU(void)	{	return (m_testMode == SR_NLU_BATCH_SR_NLU);	}
	bool isTestSR(void)		{	return (m_testMode == SR_NLU_BATCH_SR);		}
	void setTestMode(SRNLUBatchTestMode mode)	{	m_testMode = mode;		}
	void logTestResult(SRNLUResult result);
	void endLogResult()		{	
		hrlFile.closeFile();	
		outputFile.closeOutFile();
		m_currentLine = "";
	}

private:
	SRNLUBatchTester();
	~SRNLUBatchTester(void);
	
	static SRNLUBatchTester* m_pInstance;

	SRNLUBatchTestMode m_testMode;
	std::vector<std::string> m_fields;

	UIFile outputFile;
	UIFile hrlFile;
	std::string m_currentLine;
};
